package drds.global_transaction.resource_manager.sql_recognizer.impl;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;

import drds.global_transaction.resource_manager.ParameterObjectList;
import drds.global_transaction.resource_manager.sql_recognizer.SelectSqlWhereConditionRecognizer;
import drds.global_transaction.resource_manager.sql_recognizer.SqlParseException;
import drds.global_transaction.resource_manager.sql_recognizer.SqlType;

public class SelectForUpdateSqlRecognizer extends AbstractSqlRecognizer implements SelectSqlWhereConditionRecognizer
{

	private final SQLSelectStatement sqlSelectStatement;

	public SelectForUpdateSqlRecognizer(String originalSql, SQLStatement sqlSelectStatement)
	{
		super(originalSql);
		this.sqlSelectStatement = (SQLSelectStatement) sqlSelectStatement;
	}

	@Override
	public SqlType getSqlType()
	{
		return SqlType.select_for_update;
	}

	@Override
	public String getTableSource()
	{
		SQLSelectQueryBlock sqlSelectQueryBlock = getSelect();
		SQLTableSource sqlTableSource = sqlSelectQueryBlock.getFrom();
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb);
		mySqlOutputVisitor.visit((SQLExprTableSource) sqlTableSource);
		return sb.toString();
	}

	@Override
	public String getTableName()
	{
		SQLSelectQueryBlock sqlSelectQueryBlock = getSelect();
		SQLTableSource sqlTableSource = sqlSelectQueryBlock.getFrom();
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb)
		{
			@Override
			public boolean visit(SQLExprTableSource sqlExprTableSource)
			{
				printTableSourceExpr(sqlExprTableSource.getExpr());
				return false;
			}
		};
		mySqlOutputVisitor.visit((SQLExprTableSource) sqlTableSource);
		return sb.toString();
	}

	//
	@Override
	public String getWhereCondition(final ParameterObjectList parameterObjectList, final ArrayList<Object> paramAppender)
	{
		SQLSelectQueryBlock sqlSelectQueryBlock = getSelect();
		SQLExpr where = sqlSelectQueryBlock.getWhere();
		if (where == null)
		{
			return "";
		}
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb)
		{
			@Override
			public boolean visit(SQLVariantRefExpr sqlVariantRefExpr)
			{
				if ("?".equals(sqlVariantRefExpr.getName()))
				{
					List<Object> objectList = parameterObjectList.getParameterObjectList()[sqlVariantRefExpr.getIndex()];
					paramAppender.add(objectList.get(0));
				}
				return super.visit(sqlVariantRefExpr);
			}
		};
		mySqlOutputVisitor.visit((SQLBinaryOpExpr) where);
		return sb.toString();
	}

	@Override
	public String getWhereCondition()
	{
		SQLSelectQueryBlock sqlSelectQueryBlock = getSelect();
		SQLExpr where = sqlSelectQueryBlock.getWhere();
		if (where == null)
		{
			return "";
		}
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb);
		mySqlOutputVisitor.visit((SQLBinaryOpExpr) where);
		return sb.toString();
	}

	private SQLSelectQueryBlock getSelect()
	{
		SQLSelect sqlSelect = sqlSelectStatement.getSelect();
		if (sqlSelect == null)
		{
			throw new SqlParseException("should never happen!");
		}
		SQLSelectQueryBlock sqlSelectQueryBlock = sqlSelect.getQueryBlock();
		if (sqlSelectQueryBlock == null)
		{
			throw new SqlParseException("should never happen!");
		}
		return sqlSelectQueryBlock;
	}

}
